package com.zhituanbox.extensions;

import com.zhituanbox.extensions.config.ExtensionsMessageSourceModeEnum;
import com.zhituanbox.extensions.config.ExtensionsMessageSourceProperties;
import com.zhituanbox.extensions.core.validator.ExtensionsResourceBundleLocator;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator;
import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.core.Ordered;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MessageSourceResourceBundleLocator;

import javax.validation.MessageInterpolator;
import javax.validation.Validator;
import java.util.function.Supplier;

/**
 * Validator对象默认校验不会读取MessageSource内容，通过扩展配置，达到{@link javax.validation.constraints.NotBlank}等注解时，也能读取扩展信息
 *
 * @author LiuYang
 * @since 2020/9/22
 * @version 1.0.0
 */
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@EnableConfigurationProperties
@ConditionalOnProperty(prefix = "spring.messages.extensions", value = "enable", havingValue = "true", matchIfMissing = true)
@AutoConfigureAfter(ExtensionsMessageSourceAutoConfiguration.class)
public class ExtensionsValidatorAutoConfiguration {

    private final Logger log = LoggerFactory.getLogger(ExtensionsValidatorAutoConfiguration.class);

    /**
     * 加载Validator bean
     *
     * @return Validator
     * @param extensionsProperties a {@link com.zhituanbox.extensions.config.ExtensionsMessageSourceProperties} object.
     * @param messageSource a {@link org.springframework.context.MessageSource} object.
     */
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @ConditionalOnMissingBean(Validator.class)
    @ConditionalOnBean(MessageSource.class)
    public Validator defaultValidator(ExtensionsMessageSourceProperties extensionsProperties, MessageSource messageSource) {
        ExtensionsMessageSourceModeEnum mode = extensionsProperties.getMode();
        log.info("Validator mode is {}({})", mode, mode.getDesc());

        ResourceBundleLocator beforeResourceBundleLocator = null;
        ResourceBundleLocator afterResourceBundleLocator = null;
        Supplier<ResourceBundleLocator> getMessageSourceResourceBundleLocator = () -> new MessageSourceResourceBundleLocator(messageSource);
        Supplier<ResourceBundleLocator> getPlatformResourceBundleLocator = () -> new PlatformResourceBundleLocator(ResourceBundleMessageInterpolator.USER_VALIDATION_MESSAGES);
        switch (mode) {
            case ONLY_EXTENSIONS:
                beforeResourceBundleLocator = getMessageSourceResourceBundleLocator.get();
                break;
            case DEFAULT_THEN_EXTENSIONS:
                beforeResourceBundleLocator = getPlatformResourceBundleLocator.get();
                afterResourceBundleLocator = getMessageSourceResourceBundleLocator.get();
                break;
            case EXTENSIONS_THEN_DEFAULT:
                beforeResourceBundleLocator = getMessageSourceResourceBundleLocator.get();
                afterResourceBundleLocator = getPlatformResourceBundleLocator.get();
                break;
            default:
                afterResourceBundleLocator = getPlatformResourceBundleLocator.get();
        }
        ExtensionsResourceBundleLocator extensionsResourceBundleLocator = new ExtensionsResourceBundleLocator(beforeResourceBundleLocator, afterResourceBundleLocator);
        MessageInterpolator resourceBundleMessageInterpolator = new ResourceBundleMessageInterpolator(extensionsResourceBundleLocator, null, false);
//        LocaleContextMessageInterpolator localeContextMessageInterpolator = new LocaleContextMessageInterpolator(resourceBundleMessageInterpolator);
        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
        factoryBean.setMessageInterpolator(resourceBundleMessageInterpolator);
        return factoryBean;
    }
}
